﻿using System;
using System.Runtime.InteropServices;
namespace WfConnectGL
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct PIXELFORMATDESCRIPTOR
    {
        /// <summary>
        /// 
        /// </summary>
        public ushort nSize;
        public ushort nVersion;
        public uint dwFlags;
        public byte iPixelType;
        public byte cColorBits;
        public byte cRedBits;
        public byte cRedShift;
        public byte cGreenBits;
        public byte cGreenShift;
        public byte cBlueBits;
        public byte cBlueShift;
        public byte cAlphaBits;
        public byte cAlphaShift;
        public byte cAccumBits;
        public byte cAccumRedBits;
        public byte cAccumGreenBits;
        public byte cAccumBlueBits;
        public byte cAccumAlphaBits;
        public byte cDepthBits;
        public byte cStencilBits;
        public byte cAuxBuffers;
        public byte iLayerType;
        public byte bReserved;
        public uint dwLayerMask;
        public uint dwVisibleMask;
        public uint dwDamageMask;
    };

    public class PFD
    {
        public const uint TYPE_RGBA = 0;
        public const uint TYPE_COLORINDEX = 1;

        /* layer types */
        public const uint MAIN_PLANE = 0;
        public const uint OVERLAY_PLANE = 1;
        public const int UNDERLAY_PLANE = (-1);

        /* PIXELFORMATDESCRIPTOR flags */
        public const uint DOUBLEBUFFER = 0x00000001;
        public const uint STEREO = 0x00000002;
        public const uint DRAW_TO_WINDOW = 0x00000004;
        public const uint DRAW_TO_BITMAP = 0x00000008;
        public const uint SUPPORT_GDI = 0x00000010;
        public const uint SUPPORT_OPENGL = 0x00000020;
        public const uint GENERIC_FORMAT = 0x00000040;
        public const uint NEED_PALETTE = 0x00000080;
        public const uint NEED_SYSTEM_PALETTE = 0x00000100;
        public const uint SWAP_EXCHANGE = 0x00000200;
        public const uint SWAP_COPY = 0x00000400;
        public const uint SWAP_LAYER_BUFFERS = 0x00000800;
        public const uint GENERIC_ACCELERATED = 0x00001000;
        public const uint SUPPORT_DIRECTDRAW = 0x00002000;
        public const uint DIRECT3D_ACCELERATED = 0x00004000;
        public const uint SUPPORT_COMPOSITION = 0x00008000;

        /* PIXELFORMATDESCRIPTOR flags for use in ChoosePixelFormat only */
        public const uint DEPTH_DONTCARE = 0x20000000;
        public const uint DOUBLEBUFFER_DONTCARE = 0x40000000;
        public const uint STEREO_DONTCARE = 0x80000000;
    }

    internal class winapi
    {
        [DllImport("user32.dll", ExactSpelling = false, EntryPoint = "GetDC", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("gdi32.dll", ExactSpelling = false, EntryPoint = "ChoosePixelFormat", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int ChoosePixelFormat(IntPtr hdc, IntPtr ppfd);

        [DllImport("gdi32.dll", ExactSpelling = false, EntryPoint = "SetPixelFormat", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool SetPixelFormat(IntPtr hdc, int format, IntPtr ppfd);

        [DllImport("gdi32.dll", ExactSpelling = false, EntryPoint = "SwapBuffers", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool SwapBuffers(IntPtr hdc);
    }

    internal class wgl
    {
        [DllImport("opengl32.dll", ExactSpelling = false, EntryPoint = "wglCreateContext", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr CreateContext(IntPtr hdc);

        [DllImport("opengl32.dll", ExactSpelling = false, EntryPoint = "wglMakeCurrent", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool MakeCurrent(IntPtr hdc, IntPtr hglrc);

        [DllImport("opengl32.dll", ExactSpelling = false, EntryPoint = "wglDeleteContext", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        public static extern bool DeleteContext(IntPtr hglrc);
    }
    public class GLRC
    {
        private IntPtr hwnd;
        private IntPtr hdc;
        private IntPtr hglrc;
        private int PixelFormat;
        public GLRC(IntPtr haddle)
        {
            PIXELFORMATDESCRIPTOR pfd;
            pfd.nSize = 40;
            pfd.nVersion = 1;
            pfd.dwFlags = PFD.DRAW_TO_WINDOW | PFD.DRAW_TO_BITMAP | PFD.SUPPORT_OPENGL | PFD.DOUBLEBUFFER;
            pfd.iPixelType = (byte)PFD.TYPE_RGBA;
            pfd.cColorBits = 32;
            pfd.cRedBits = 0;
            pfd.cRedShift = 0;
            pfd.cGreenBits = 0;
            pfd.cGreenShift = 0;
            pfd.cBlueBits = 0;
            pfd.cBlueShift = 0;
            pfd.cAlphaBits = 0;
            pfd.cAlphaShift = 0;
            pfd.cAccumBits = 0;
            pfd.cAccumRedBits = 0;
            pfd.cAccumGreenBits = 0;
            pfd.cAccumBlueBits = 0;
            pfd.cAccumAlphaBits = 0;
            pfd.cDepthBits = 16;
            pfd.cStencilBits = 0;
            pfd.cAuxBuffers = 0;
            pfd.iLayerType = (byte)PFD.MAIN_PLANE;
            pfd.bReserved = 0;
            pfd.dwLayerMask = 0;
            pfd.dwVisibleMask = 0;
            pfd.dwDamageMask = 0;
            CreateRC(haddle, pfd);
        }

        private void CreateRC(IntPtr haddle, PIXELFORMATDESCRIPTOR pfd)
        {
            this.hwnd = haddle;
            this.hdc = winapi.GetDC(haddle);
            unsafe
            {
                PIXELFORMATDESCRIPTOR* ppfd = &pfd;
                this.PixelFormat = winapi.ChoosePixelFormat(this.hdc, (IntPtr)ppfd);
                winapi.SetPixelFormat(this.hdc, this.PixelFormat, (IntPtr)ppfd);
                this.hglrc = wgl.CreateContext(this.hdc);
                wgl.MakeCurrent(this.hdc, this.hglrc);
            }
        }

        public bool MakeCurrent()
        {
            return wgl.MakeCurrent(this.hdc, this.hglrc);
        }

        public bool ReleaseCurrent()
        {
            return wgl.MakeCurrent(this.hdc, IntPtr.Zero);
        }

        public bool DeleteRC()
        {
            return wgl.DeleteContext(this.hglrc);
        }

        public void SwapBuffers()
        {
            winapi.SwapBuffers(this.hdc);
        }
    }
}
